package com.yida.gwj.report.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.yida.common.core.constant.SecurityConstants;
import com.yida.common.core.exception.ServiceException;
import com.yida.common.core.utils.DateUtils;
import com.yida.common.core.utils.PageUtils;
import com.yida.common.core.utils.StringUtils;
import com.yida.common.security.utils.SecurityUtils;
import com.yida.gwj.api.domain.GwjFinanceAccountDetail;
import com.yida.gwj.api.domain.request.RemoteAccountDetailForRateRequest;
import com.yida.gwj.api.service.RemoteGwjFinanceService;
import com.yida.gwj.common.constant.GwjConstants;
import com.yida.gwj.common.domain.GwjBaseBuild;
import com.yida.gwj.common.domain.GwjBaseCommunity;
import com.yida.gwj.common.domain.GwjBaseHouse;
import com.yida.gwj.common.mapper.GwjBaseHouseMapper;
import com.yida.gwj.common.service.IGwjBaseBuildService;
import com.yida.gwj.common.service.IGwjBaseCommunityService;
import com.yida.gwj.common.service.IGwjBaseHouseService;
import com.yida.gwj.common.utils.GwjConvertUtil;
import com.yida.gwj.report.annotation.CalculateRateLog;
import com.yida.gwj.report.config.CalculateRateConfig;
import com.yida.gwj.report.domain.GwjCalculateRateLog;
import com.yida.gwj.report.domain.GwjReportYearBenifit;
import com.yida.gwj.report.domain.GwjSysCalculateRate;
import com.yida.gwj.report.domain.dto.GwjCalculateRateDTO;
import com.yida.gwj.report.domain.request.GwjCalculateRateRequest;
import com.yida.gwj.report.domain.request.GwjReportYearBenifitRequest;
import com.yida.gwj.report.domain.request.GwjSettleRateRequest;
import com.yida.gwj.report.domain.vo.GwjHouseDepositVO;
import com.yida.gwj.report.domain.vo.GwjSettleRateVO;
import com.yida.gwj.report.mapper.*;
import com.yida.gwj.report.service.IGwjCalculateRateLogService;
import com.yida.gwj.report.service.IGwjCalculateRateService;
import com.yida.gwj.report.service.IGwjSysCalculateRateService;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Author: PPV
 * @Date: 2023-03-08
 */
@Service
public class GwjCalculateRateServiceImpl implements IGwjCalculateRateService {

    @Resource
    private GwjReportYearBenifitMapper yearBenifitMapper;

    @Resource
    private IGwjBaseCommunityService communityService;

    @Resource
    private IGwjBaseBuildService buildService;

    @Resource
    private IGwjBaseHouseService houseService;

    @Resource
    private RemoteGwjFinanceService remoteGwjFinanceService;

    @Resource
    private IGwjCalculateRateLogService logService;


    @Resource
    private CalculateRateConfig config;

    @Resource
    private GwjFinanceMoneyMapper gwjFinanceMoneyMapper;

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    @Resource
    private GwjCalculateRateAreaMapper calculateRateAreaMapper;

    @Resource
    private IGwjSysCalculateRateService gwjSysCalculateRateService;

    /**
     * 计息展示计算标识
     */
    private static final String CALCULATE_SHOW_FLAG = "JustToUser";


    @Override
    public int save(GwjReportYearBenifitRequest request) {
        GwjReportYearBenifit gwjReportYearBenifit = BeanUtil.copyProperties(request, GwjReportYearBenifit.class);
        gwjReportYearBenifit.setCreateBy(SecurityUtils.getUserId().toString());
        gwjReportYearBenifit.setCreateTime(DateUtils.getNowDate());
        return yearBenifitMapper.insertGwjReportYearBenifit(gwjReportYearBenifit);
    }

    @Override
    public int update(GwjReportYearBenifitRequest request) {
        GwjReportYearBenifit gwjReportYearBenifit = BeanUtil.copyProperties(request, GwjReportYearBenifit.class);
        gwjReportYearBenifit.setUpdateBy(SecurityUtils.getUserId().toString());
        gwjReportYearBenifit.setUpdateTime(DateUtils.getNowDate());
        return yearBenifitMapper.updateGwjReportYearBenifit(gwjReportYearBenifit);
    }

    @Override
    public int delBatch(Long[] benefitIds) {
        return yearBenifitMapper.deleteGwjReportYearBenifitByBenefitIds(benefitIds);
    }

    @Override
    public List<GwjReportYearBenifit> getPage(String year, String status) {
        PageUtils.startPage();
        HashMap<String, Object> paramMap = new HashMap<>(2);
        if (StrUtil.isNotBlank(year)) {
            paramMap.put("year", year);
        }
        if (StrUtil.isNotBlank(status)) {
            paramMap.put("status", status);
        }
        return yearBenifitMapper.getPage(paramMap);
    }

    @Override
    public int confirm(Long benefitId) {
        GwjReportYearBenifit gwjReportYearBenifit = yearBenifitMapper.selectGwjReportYearBenifitByBenefitId(benefitId);
        gwjReportYearBenifit.setStatus(GwjConstants.YES);
        return yearBenifitMapper.updateGwjReportYearBenifit(gwjReportYearBenifit);
    }

    @Override
    public GwjCalculateRateDTO calculateRateShow(GwjCalculateRateRequest request) {
        GwjCalculateRateDTO dto = new GwjCalculateRateDTO();
        Long interval = request.getStartTime().until(request.getEndTime(), ChronoUnit.DAYS);
        if (interval < 1) {
            throw new ServiceException("结息日期异常，请检查后，重新输入");
        }
        //所选小区下所有房屋
        List<GwjBaseHouse> allHouses = getAllHouses(request.getCommunityId());
        //本年累计积数
        GwjCalculateRateLog yearLog = ((IGwjCalculateRateService) AopContext.currentProxy()).calculateSingleCommunity(request.getCommunityId(), allHouses, request.getStartTime(), request.getEndTime(), CALCULATE_SHOW_FLAG);
        BigDecimal yearLedgerCumulative = yearLog.getLedgerCumulative();
        //总累计计息积数
        GwjCalculateRateLog totalLog = ((IGwjCalculateRateService) AopContext.currentProxy()).calculateSingleCommunity(request.getCommunityId(), allHouses, null, request.getEndTime(), CALCULATE_SHOW_FLAG);
        BigDecimal totalLedgerCumulative = totalLog.getLedgerCumulative();

        dto.setSaveDays(interval);
        dto.setLedgerMoney(getLedgerMoney(allHouses));
        dto.setLedgerCumulative(yearLedgerCumulative);
        dto.setDayRate(getDayRate(request.getYearBenefit(), yearLedgerCumulative));
        dto.setInterestMoney(getInterestMoney(totalLedgerCumulative, dto.getDayRate()));
        dto.setTotalMoney(dto.getLedgerMoney().add(dto.getInterestMoney()).setScale(2, BigDecimal.ROUND_HALF_UP));

        return dto;
    }

    @Override
    @CalculateRateLog(CalculateRateLog.LogType.AREA)
    public GwjCalculateRateLog settleRate(GwjSettleRateRequest request) {
        String calculateFlag = generateCalculateFlag(request.getAreaId());
        List<GwjBaseCommunity> communities = communityService.selectGwjBaseCommunityList(new GwjBaseCommunity() {{
            setAreaId(request.getAreaId());
        }});

        //计算地区下所有小区本年累计积数
        GwjConvertUtil.partition(communities, config.getCommunityBatchArg()).stream().flatMap(subList -> subList.stream()).forEach(item -> calculateSingleCommunity(item.getCommunityId(), getAllHouses(item.getCommunityId()), request.getStartTime(), request.getEndTime(), calculateFlag));

        //等待小区计息结果后   计算并记录结息结果
        BigDecimal ledgerCumulative = logService.listCommunityLogs(request.getAreaId(), calculateFlag).stream().map(GwjCalculateRateLog::getLedgerCumulative).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal dayRate = getDayRate(request.getYearBenefit(), ledgerCumulative);
        GwjCalculateRateLog log = new GwjCalculateRateLog() {{
            setAreaId(request.getAreaId());
            setStartTime(request.getStartTime());
            setEndTime(request.getEndTime());
            setYearBenefit(request.getYearBenefit());
            setLedgerCumulative(ledgerCumulative);
            setDayRate(dayRate);
            setCalculateFlag(calculateFlag);
        }};

        //批量结算房屋利息并更新
        List<GwjCalculateRateLog> houseLogs = logService.listHouseLogs(request.getAreaId(), calculateFlag);
        List<GwjBaseHouse> updateList = GwjConvertUtil.partition(houseLogs, config.getLogBatchArg()).stream().flatMap(subList -> subList.stream()).map(item -> {
            GwjBaseHouse house = new GwjBaseHouse() {{
                setAreaId(item.getAreaId());
                setHouseCode(item.getHouseCode());
            }};
            house.setInterestMoney(getInterestMoney(item.getLedgerCumulative(), dayRate));
            return house;
        }).collect(Collectors.toList());
        GwjConvertUtil.partition(updateList, config.getHouseBatchArg()).stream().forEach(item -> houseService.updateBatchGwjBaseHouseByHouseCode(item));

        return log;
    }


    /**
     * 根据房屋列表计息 （用于线程调用）
     *
     * @param communityId
     * @param allHouses
     * @param startTime
     * @param endTime
     * @param calculateFlag
     */
    public void calculateHouseList(Long communityId, List<GwjBaseHouse> allHouses, LocalDate startTime, LocalDate endTime, String calculateFlag) {
        AtomicReference<BigDecimal> totalCumulative = new AtomicReference<>(new BigDecimal("0.00"));

        GwjConvertUtil.partition(allHouses, config.getHouseBatchArg()).stream().forEach(partHouses -> {
            //========================================查询分类账列表======================================================
            List<GwjFinanceAccountDetail> details;
            try {
                details = remoteGwjFinanceService.getListForRate(new RemoteAccountDetailForRateRequest() {{
                    setAreaId(partHouses.get(0).getAreaId());
                    setStartTime(startTime);
                    setEndTime(endTime);
                    setHouseCodes((ArrayList<String>) partHouses.stream().map(GwjBaseHouse::getHouseCode).collect(Collectors.toList()));
                }}, SecurityConstants.INNER).getData();
                if (CollUtil.isEmpty(details)) {
                    throw new NullPointerException();
                }
            } catch (Exception e) {
                throw new ServiceException("查询分账列表失败");
            }
            //======================================计算房屋累计计息积数===================================================
            for (GwjBaseHouse house : partHouses) {
                GwjCalculateRateLog log = ((IGwjCalculateRateService) AopContext.currentProxy()).calculateSingleHouse(house, details, startTime, endTime, calculateFlag, communityId);
                //计算小区累计计息积数
                totalCumulative.set(totalCumulative.get().add(log.getLedgerCumulative()).setScale(2, BigDecimal.ROUND_HALF_UP));
            }
        });
    }

    /**
     * 保存小区计息日志
     *
     * @param communityId
     * @param calculateFlag
     */
    public void saveCalculateCommunityLog(Long communityId, String calculateFlag) {
        //查询小区所有房屋的计息日志
        List<GwjCalculateRateLog> logs = logService.listHouseLogs4Community(communityId, calculateFlag);
        GwjCalculateRateLog log = new GwjCalculateRateLog() {{
            setAreaId(logs.get(0).getAreaId());
            setCommunityId(communityId);
            setStartTime(logs.get(0).getStartTime());
            setEndTime(logs.get(0).getEndTime());
            setLedgerCumulative(logs.stream().map(GwjCalculateRateLog::getLedgerCumulative).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP));
            setCalculateFlag(calculateFlag);
        }};
        logService.saveLog(log, CalculateRateLog.LogType.COMMUNITY);
    }

    /**
     * 单个小区计息
     *
     * @param communityId   小区id
     * @param allHouses     小区下房屋列表
     * @param startTime     计息开始时间
     * @param endTime       计息结束时间
     * @param calculateFlag 计算标识
     * @return
     */
    @CalculateRateLog(CalculateRateLog.LogType.COMMUNITY)
    public GwjCalculateRateLog calculateSingleCommunity(Long communityId, List<GwjBaseHouse> allHouses, LocalDate startTime, LocalDate endTime, String calculateFlag) {
        AtomicReference<BigDecimal> totalCumulative = new AtomicReference<>(new BigDecimal("0.00"));

        for (List<GwjBaseHouse> partHouses : GwjConvertUtil.partition(allHouses, config.getHouseBatchArg())) {
            //========================================查询分类账列表======================================================
            List<GwjFinanceAccountDetail> details;
            try {
                details = remoteGwjFinanceService.getListForRate(new RemoteAccountDetailForRateRequest() {{
                    setAreaId(partHouses.get(0).getAreaId());
                    setStartTime(startTime);
                    setEndTime(endTime);
                    setHouseCodes((ArrayList<String>) partHouses.stream().map(GwjBaseHouse::getHouseCode).collect(Collectors.toList()));
                }}, SecurityConstants.INNER).getData();
                if (CollUtil.isEmpty(details)) {
                    continue;
                }
            } catch (Exception e) {
                throw new ServiceException("查询分账列表失败");
            }
            //======================================计算房屋累计计息积数===================================================
            for (GwjBaseHouse house : partHouses) {
                GwjCalculateRateLog log = ((IGwjCalculateRateService) AopContext.currentProxy()).calculateSingleHouse(house, details, startTime, endTime, calculateFlag, communityId);
                // 判断日志是否为空 2023/08/23
                if (ObjectUtil.isNotEmpty(log.getLedgerCumulative())) {
                    //计算小区累计计息积数
                    totalCumulative.set(totalCumulative.get().add(log.getLedgerCumulative()).setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            }
        }
        ;

        //记录小区计息结果
        GwjCalculateRateLog log = new GwjCalculateRateLog() {{
            setAreaId(allHouses.get(0).getAreaId());
            setCommunityId(communityId);
            setStartTime(startTime);
            setEndTime(endTime);
            setLedgerCumulative(totalCumulative.get());
            setCalculateFlag(calculateFlag);
        }};

        return log;
    }

    /**
     * 单间房屋计息
     * 思路:
     * n条分账对应 n条房屋金额变化  n + 1个时间间隔
     * 总偏移量 = 每次偏移量（之前所有偏移量之和） * 持续时间
     * 累计计息积数 = 总基准值（当前余额 * 结息起止时间间隔） + 总偏移量
     * eg：
     * -------- startTime
     * 10   1
     * --------- dealTime1    变化量 -2
     * 8    2
     * --------- dealTime2    变化量 +6
     * 14   3
     * -------- endTime
     * 以14作为基准值（当前余额）  14*（1+2+3） = 84 即总基准值
     * 8 - 14 = -6   -6 * 2 = -12                  注意：此处偏移量是 -6  是之前余额相对于当前余额的偏移
     * 10 - 8 = 2  2 + （-6） = -4  -4 * 1 = -4     注意：此处偏移量为 -4  是两次变化量之和
     * -12 + （-4） = -16  即  总偏移量
     * 84 + （-16） = 68   即  累计计息积数 =  10*1 + 8*2 + 14*3 = 68
     *
     * @param house         房屋
     * @param details       分账列表
     * @param startTime     计息开始时间
     * @param endTime       计息结束时间
     * @param calculateFlag 计算标识
     * @return
     */
    @CalculateRateLog(CalculateRateLog.LogType.HOUSE)
    @Transactional(rollbackFor = Exception.class)
    public GwjCalculateRateLog calculateSingleHouse(GwjBaseHouse house, List<GwjFinanceAccountDetail> details, LocalDate startTime, LocalDate endTime, String calculateFlag, Long communityId) {

        //过滤出属于该房屋的分类账集合
        details = details.stream().filter(item -> house.getHouseCode().equals(item.getHouseCode())).collect(Collectors.toList());
        // 判断分类账是否为空 2023/08/23
        if (ObjectUtil.isEmpty(details)) {
            return new GwjCalculateRateLog();
        }
        //计算总间隔天数
        LocalDate dealTime = date2LocalDate(details.get(details.size() - 1).getDealTime());
        Long interval = dealTime.until(endTime, ChronoUnit.DAYS);
        Long extraDays = 0L;

        if (startTime != null) {
            interval = startTime.until(endTime, ChronoUnit.DAYS);
            extraDays = startTime.until(dealTime, ChronoUnit.DAYS);
        }

        //计算每个房屋基准值
        BigDecimal base = house.getCurrentMoney().multiply(new BigDecimal(interval.toString())).setScale(2, BigDecimal.ROUND_HALF_UP);
        //偏移量 = 之前所有偏移量的累计
        BigDecimal offset = new BigDecimal("0.00");
        //总偏移量 = 偏移量 * 持续时间 (即两条分账记录的间隔天数)
        BigDecimal totalOffset = new BigDecimal("0.00");
        //计算每个房屋累计计息积数 = 基准值 + 总偏移量
        BigDecimal cumulative;
        //分账记录只有一条则偏移持续时间为0 则总偏移量为0
        if (details.size() != 1) {
            for (int i = 0; i < details.size() - 1; i++) {
                GwjFinanceAccountDetail item = details.get(i);
                LocalDate baseTime = date2LocalDate(item.getDealTime());
                LocalDate changeTime = date2LocalDate(details.get(i + 1).getDealTime());
                Long duration = changeTime.until(baseTime, ChronoUnit.DAYS);
                //计算 偏移量
                if (BigDecimal.ZERO.compareTo(item.getIncomeMoney()) == 1 || BigDecimal.ZERO.compareTo(item.getPayMoney()) == 1) {
                    throw new ServiceException("分类账金额不得为负,账目id：" + item.getAccountDetailId() + ",请及时联系管理员");
                }
                if (BigDecimal.ZERO.compareTo(item.getIncomeMoney()) != 0) {
                    offset = offset.subtract(item.getIncomeMoney()).setScale(2, BigDecimal.ROUND_HALF_UP);
                } else {
                    offset = offset.add(item.getPayMoney()).setScale(2, BigDecimal.ROUND_HALF_UP);
                }
                //计算 总偏移量
                totalOffset = totalOffset.add(offset.multiply(new BigDecimal(duration.toString())).setScale(2, BigDecimal.ROUND_HALF_UP)).setScale(2, BigDecimal.ROUND_HALF_UP);
            }
            //有startTime，计算总偏移量时，应当包括从startTime到第一次分账dealTime的偏移量
            if (extraDays != 0) {
                totalOffset = totalOffset.add(offset.multiply(new BigDecimal(extraDays.toString())).setScale(2, BigDecimal.ROUND_HALF_UP)).setScale(2, BigDecimal.ROUND_HALF_UP);
            }
        }
        cumulative = base.add(totalOffset).setScale(2, BigDecimal.ROUND_HALF_UP);

        //记录房屋计息结果
        GwjCalculateRateLog log = new GwjCalculateRateLog() {{
            setAreaId(house.getAreaId());
            setHouseCode(house.getHouseCode());
            setLedgerCumulative(cumulative);
            setCalculateFlag(calculateFlag);
            setCommunityId(communityId);
        }};

        return log;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void interest2Money(Long areaId, String calculateFlag) {
        // 查询对应房屋结息日志信息
        List<GwjCalculateRateLog> gwjCalculateRateLogs = logService.listHouseLogs(areaId, calculateFlag);
        // 判断房屋结息日志是否为空
        if (ObjectUtil.isEmpty(gwjCalculateRateLogs)) {
            throw new ServiceException("未查询到对应房屋结息日志");
        }
        // 房屋日志对象转房屋编号集合
        List<String> houseCodeList = gwjCalculateRateLogs.stream().map(item -> item.getHouseCode()).collect(Collectors.toList());
        // 批量更新房屋结息日志信息
        SqlSession houseLogSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GwjCalculateRateHouseMapper calculateRateHouseMapper = houseLogSqlSession.getMapper(GwjCalculateRateHouseMapper.class);
        List<GwjCalculateRateLog> editHouseLogList = new ArrayList<>();
        try {
            GwjCalculateRateLog houseLog = new GwjCalculateRateLog();
            for (int i = 1; i - 1 < gwjCalculateRateLogs.size(); i++) {
                houseLog.setHouseCode(gwjCalculateRateLogs.get(i - 1).getHouseCode());
                // 修改为已结息
//                houseLog.setSettleFlag("1");
                editHouseLogList.add(houseLog);
                houseLog = new GwjCalculateRateLog();
                // 2000条更新一次
                if (i % 200 == 0) {
                    calculateRateHouseMapper.editSettleFlag(editHouseLogList);
                    editHouseLogList.clear();
                    houseLogSqlSession.commit();
                }
            }
            // 剩余数据更新
            if (ObjectUtil.isNotEmpty(editHouseLogList)) {
                calculateRateHouseMapper.editSettleFlag(editHouseLogList);
                editHouseLogList.clear();
                houseLogSqlSession.commit();
            }
        } catch (Exception e) {
            // 报错回滚
            houseLogSqlSession.rollback();
            throw new ServiceException(e.getMessage());
        } finally {
            // 清除缓存
            houseLogSqlSession.clearCache();
            // 关闭连接
            houseLogSqlSession.close();

        }
        // 批量更新基础房屋信息
        SqlSession baseHouseSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GwjBaseHouseMapper baseHouseMapper = baseHouseSqlSession.getMapper(GwjBaseHouseMapper.class);
        List<String> editHouseCodeList = new ArrayList<>();
        try {
            for (int i = 1; i - 1 < houseCodeList.size(); i++) {
                editHouseCodeList.add(houseCodeList.get(i - 1));
                // 2000条更新一次
                if (i % 200 == 0) {
                    // 查询基础房屋信息
                    List<GwjBaseHouse> baseHouses = baseHouseMapper.selectGwjBaseListByHouseCode(editHouseCodeList.stream().toArray(String[]::new));
                    // 赋值业务信息
                    baseHouses = baseHouses.stream().map(item -> {
                        // 息转本
                        item.setCurrentMoney(item.getCurrentMoney().add(item.getInterestMoney()));
                        // 清空利息
                        item.setInterestMoney(BigDecimal.ZERO);
                        item.setUpdateTime(new Date());
                        item.setUpdateBy(SecurityUtils.getUsername());
                        return item;
                    }).collect(Collectors.toList());
                    // 清空集合
                    editHouseCodeList.clear();
                    // 批量更新基础数据库
                    baseHouseMapper.updateBatchGwjBaseHouse(baseHouses);
                    // 数据提交
                    baseHouseSqlSession.commit();
                }

            }
            // 处理剩余基础房屋信息
            if (ObjectUtil.isNotEmpty(editHouseCodeList)) {
                // 查询基础房屋信息
                List<GwjBaseHouse> baseHouses = baseHouseMapper.selectGwjBaseListByHouseCode(editHouseCodeList.stream().toArray(String[]::new));
                // 更新业务数据
                baseHouses = baseHouses.stream().map(item -> {
                    // 息转本
                    item.setCurrentMoney(item.getCurrentMoney().add(item.getInterestMoney()));
                    // 清空利息
                    item.setInterestMoney(BigDecimal.ZERO);
                    item.setUpdateTime(new Date());
                    item.setUpdateBy(SecurityUtils.getUsername());
                    return item;
                }).collect(Collectors.toList());
                // 清空集合数据
                editHouseCodeList.clear();
                // 批量更新基础房屋数据
                baseHouseMapper.updateBatchGwjBaseHouse(baseHouses);
                // 业务提交至数据库
                baseHouseSqlSession.commit();
            }
        } catch (Exception e) {
            // 报错回滚
            baseHouseSqlSession.rollback();
            throw new ServiceException(e.getMessage());
        } finally {
            // 清除缓存
            baseHouseSqlSession.clearCache();
            // 连接关闭
            baseHouseSqlSession.close();
        }

    }

    /**
     * 地区结息-新
     *
     * @param request 地区结息请求参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void newSettleRate(GwjSettleRateRequest request) {
        GwjSysCalculateRate sysCalculateRate = gwjSysCalculateRateService.selectGwjSysCalculateRateById(request.getId());
        if (ObjectUtil.isNull(sysCalculateRate)){
            throw new ServiceException("查无系统结息配置");
        }
        if (sysCalculateRate.getDayRate() != null){
            throw new ServiceException("该日期已经结息");
        }
        request.setAreaId(sysCalculateRate.getAreaId());
        request.setEndTime(sysCalculateRate.getCalculateTime());
        request.setYearBenefit(sysCalculateRate.getYearBenefit());
        //设置开始时间
        request.setStartTime(getStartTime(request.getAreaId(), request.getEndTime()));
        // 计算房屋利息、累计计息基数
        Map<String, GwjSettleRateVO> houseSettleRateMap = getHouseSettleRate(request);
        // 计算社区利息、累计计息基数
        Map<Long, GwjSettleRateVO> communitySettleRateMap = new HashMap<Long, GwjSettleRateVO>();
        for (Map.Entry<String, GwjSettleRateVO> item : houseSettleRateMap.entrySet()) {
            GwjSettleRateVO vo = item.getValue();
            GwjSettleRateVO communityDetail = communitySettleRateMap.get(vo.getCommunityId());
            // 判断社区详情是否为空
            if (ObjectUtil.isNotEmpty(communityDetail)) {
                // 累计计息基数
                communityDetail.setLedgerCumulative(communityDetail.getLedgerCumulative().add(vo.getLedgerCumulative()));
                // 累计利息
                communityDetail.setInterest(communityDetail.getInterest().add(vo.getInterest()));
                // 重新赋值社区详情
                communitySettleRateMap.put(vo.getCommunityId(), communityDetail);
            } else {
                communityDetail = new GwjSettleRateVO();
                communityDetail.setCommunityId(vo.getCommunityId());
                communityDetail.setInterest(vo.getInterest());
                communityDetail.setLedgerCumulative(vo.getLedgerCumulative());
                communityDetail.setDayRate(vo.getDayRate());
                communitySettleRateMap.put(vo.getCommunityId(), communityDetail);
            }
        }
        // 计算区域累计计息基数、于利息
        BigDecimal totalLedgerCumulative = BigDecimal.ZERO;
        BigDecimal totalInterest = BigDecimal.ZERO;
        for (Map.Entry<Long, GwjSettleRateVO> item : communitySettleRateMap.entrySet()) {
            totalLedgerCumulative = totalLedgerCumulative.add(item.getValue().getLedgerCumulative());
            totalInterest = totalInterest.add(item.getValue().getInterest());
        }
        // 生成计算
        String calculateFlag = generateCalculateFlag(request.getAreaId());
        // 房屋map转换为list
        List<GwjCalculateRateLog> houseLogList = houseSettleRateMap.entrySet().stream().map(item -> {
            GwjCalculateRateLog houseLog = new GwjCalculateRateLog();
            GwjSettleRateVO gwjSettleRateVO = item.getValue();
            houseLog.setDayRate(gwjSettleRateVO.getDayRate());
            houseLog.setHouseCode(item.getKey());
            houseLog.setAreaId(request.getAreaId());
            houseLog.setInterest(gwjSettleRateVO.getInterest());
            houseLog.setLedgerCumulative(gwjSettleRateVO.getLedgerCumulative());
            houseLog.setStartTime(request.getStartTime());
            houseLog.setEndTime(request.getEndTime());
            houseLog.setCommunityId(gwjSettleRateVO.getCommunityId());
            houseLog.setCalculateFlag(calculateFlag);
            houseLog.setCreateBy(SecurityUtils.getUsername());
            return houseLog;
        }).collect(Collectors.toList());
        // 新增房屋计息日志
        // 分批提交至数据库
        SqlSession houseSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GwjCalculateRateHouseMapper calculateRateHouseMapper = houseSqlSession.getMapper(GwjCalculateRateHouseMapper.class);
        // 创建房屋计息日志对象
        List<GwjCalculateRateLog> newHouseLogList = new ArrayList<GwjCalculateRateLog>();
        // 数据库插入等待时间
        Long waitTime = 5L;
        try {
            // 分批提交
            for (int i = 1; i - 1 < houseLogList.size(); i++) {
                newHouseLogList.add(houseLogList.get(i - 1));
                // 2000条房屋日志提交一次
                if (0 == i % 2000) {
                    // 批量插入房屋计息日志
                    calculateRateHouseMapper.insertBatch(newHouseLogList);
                    // 提交至数据库
                    houseSqlSession.commit();
                    // 清空对象
                    newHouseLogList.clear();
                    // 等待数据库数据插入
//                    Thread.sleep(waitTime * 1000);
                }
            }
            // 剩余数据提交
            if (ObjectUtil.isNotEmpty(newHouseLogList)) {
                // 批量插入房屋计息日志
                calculateRateHouseMapper.insertBatch(newHouseLogList);
                // 提交至数据库
                houseSqlSession.commit();
            }
        } catch (Exception e) {
            // 数据回滚
            houseSqlSession.rollback();
            throw new ServiceException(e.getMessage());
        } finally {
            // 清楚缓存
            houseSqlSession.clearCache();
            // 关闭连接
            houseSqlSession.close();
        }
        // 房屋map转换为list
        List<GwjCalculateRateLog> communityLogList = communitySettleRateMap.entrySet().stream().map(item -> {
            GwjCalculateRateLog communityLog = new GwjCalculateRateLog();
            GwjSettleRateVO gwjSettleRateVO = item.getValue();
            communityLog.setDayRate(gwjSettleRateVO.getDayRate());
            communityLog.setCommunityId(item.getKey());
            communityLog.setAreaId(request.getAreaId());
            communityLog.setLedgerCumulative(gwjSettleRateVO.getLedgerCumulative());
            communityLog.setStartTime(request.getStartTime());
            communityLog.setEndTime(request.getEndTime());
            communityLog.setCommunityId(gwjSettleRateVO.getCommunityId());
            communityLog.setCalculateFlag(calculateFlag);
            communityLog.setCreateBy(SecurityUtils.getUsername());
            return communityLog;
        }).collect(Collectors.toList());
        // 新增社区计息日志
        SqlSession communitySqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GwjCalculateRateCommunityMapper calculateRateCommunityMapper = communitySqlSession.getMapper(GwjCalculateRateCommunityMapper.class);
        // 创建社区计息日志
        List<GwjCalculateRateLog> newCommunityLogList = new ArrayList<GwjCalculateRateLog>();
        try {
            // 分批提交
            for (int i = 1; i - 1 < communityLogList.size(); i++) {
                newCommunityLogList.add(communityLogList.get(i - 1));
                // 2000条房屋日志提交一次
                if (0 == i % 2000) {
                    // 批量插入房屋计息日志
                    calculateRateCommunityMapper.insertBatch(newCommunityLogList);
                    // 提交至数据库
                    communitySqlSession.commit();
                    // 清空对象
                    newCommunityLogList.clear();
                }
            }
            // 剩余数据提交
            if (ObjectUtil.isNotEmpty(newCommunityLogList)) {
                // 批量插入房屋计息日志
                calculateRateCommunityMapper.insertBatch(newCommunityLogList);
                // 提交至数据库
                communitySqlSession.commit();
            }
        } catch (Exception e) {
            // 数据回滚
            communitySqlSession.rollback();
            throw new ServiceException(e.getMessage());
        } finally {
            // 清楚缓存
            communitySqlSession.clearCache();
            // 关闭连接
            communitySqlSession.close();
        }
        // 更新区域计息日志
        BigDecimal areaLedgerCumulative = totalLedgerCumulative;
        SqlSession baseHouseSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GwjBaseHouseMapper baseHouseMapper = baseHouseSqlSession.getMapper(GwjBaseHouseMapper.class);
        calculateRateAreaMapper.insert(new GwjCalculateRateLog() {
            {
                setAreaId(request.getAreaId());
                setStartTime(request.getStartTime());
                setEndTime(request.getEndTime());
                setYearBenefit(request.getYearBenefit());
                setLedgerCumulative(areaLedgerCumulative);
                setDayRate(communityLogList.get(0).getDayRate());
                setCreateBy(SecurityUtils.getUsername());
            }
        });
        //更新系统计息
        gwjSysCalculateRateService.updateGwjSysCalculateRate(new GwjSysCalculateRate(){{
            setDayRate(communityLogList.get(0).getDayRate().multiply(new BigDecimal("365")));
            setId(request.getId());
        }});
        // 更新基础数据库数据
        List<String> houseCodeList = newHouseLogList.stream().map(item -> item.getHouseCode()).collect(Collectors.toList());
        List<String> editHouseCodeList = new ArrayList<>();
        try {
            // 分批查询更新基础房屋信息
            for (int i = 1; i - 1 < houseCodeList.size(); i++) {
                editHouseCodeList.add(houseCodeList.get(i - 1));
                // 分批查询插入
                if (i % 2000 == 0) {
                    // 查询基础房屋数据
                    List<GwjBaseHouse> baseHouses = houseService.selectGwjBaseListByHouseCode(editHouseCodeList.stream().toArray(String[]::new)).stream().map(item -> {
                        // 修改房屋利息
                        item.setInterestMoney(item.getInterestMoney().add(houseSettleRateMap.get(item.getHouseCode()).getInterest()));
                        item.setUpdateBy(SecurityUtils.getUsername());
                        item.setUpdateTime(new Date());
                        return item;
                    }).collect(Collectors.toList());
                    // 批量更新基础房屋数据
                    baseHouseMapper.updateBatchGwjBaseHouse(baseHouses);
                    baseHouseSqlSession.commit();
                }
            }
            // 更新剩下房屋数据
            if (ObjectUtil.isNotEmpty(editHouseCodeList)) {
                // 查询基础房屋数据
                List<GwjBaseHouse> baseHouses = houseService.selectGwjBaseListByHouseCode(editHouseCodeList.stream().toArray(String[]::new)).stream().map(item -> {
                    // 修改房屋利息
                    item.setInterestMoney(item.getInterestMoney().add(houseSettleRateMap.get(item.getHouseCode()).getInterest()));
                    item.setUpdateBy(SecurityUtils.getUsername());
                    item.setUpdateTime(new Date());
                    return item;
                }).collect(Collectors.toList());
                // 批量更新基础房屋数据
                baseHouseMapper.updateBatchGwjBaseHouse(baseHouses);
                // sql提交
                baseHouseSqlSession.commit();
            }
        } catch (Exception e) {
            // sql回滚
            baseHouseSqlSession.rollback();
            throw new ServiceException(e.getMessage());
        } finally {
            // 清除缓存
            baseHouseSqlSession.clearCache();
            // 关闭连接
            baseHouseSqlSession.close();
        }
    }


    /**
     * 全地区结息-新
     *
     * @param request 地区结息请求参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void newSettleRateAll(GwjSettleRateRequest request) {
        GwjSysCalculateRate sysCalculateRate = gwjSysCalculateRateService.selectGwjSysCalculateRateById(request.getId());
        if (ObjectUtil.isNull(sysCalculateRate)){
            throw new ServiceException("查无系统结息配置");
        }
        request.setAreaId(sysCalculateRate.getAreaId());
        request.setEndTime(sysCalculateRate.getCalculateTime());
        request.setYearBenefit(sysCalculateRate.getYearBenefit());
        //设置开始时间
        request.setStartTime(getStartTime(request.getAreaId(), request.getEndTime()));
        // 计算房屋利息、累计计息基数
        Map<String, GwjSettleRateVO> houseSettleRateMap = getHouseSettleRate(request);
        // 计算社区利息、累计计息基数
        Map<Long, GwjSettleRateVO> communitySettleRateMap = new HashMap<Long, GwjSettleRateVO>();
        for (Map.Entry<String, GwjSettleRateVO> item : houseSettleRateMap.entrySet()) {
            GwjSettleRateVO vo = item.getValue();
            GwjSettleRateVO communityDetail = communitySettleRateMap.get(vo.getCommunityId());
            // 判断社区详情是否为空
            if (ObjectUtil.isNotEmpty(communityDetail)) {
                // 累计计息基数
                communityDetail.setLedgerCumulative(communityDetail.getLedgerCumulative().add(vo.getLedgerCumulative()));
                // 累计利息
                communityDetail.setInterest(communityDetail.getInterest().add(vo.getInterest()));
                // 重新赋值社区详情
                communitySettleRateMap.put(vo.getCommunityId(), communityDetail);
            } else {
                communityDetail = new GwjSettleRateVO();
                communityDetail.setDayRate(vo.getDayRate());
                communityDetail.setCommunityId(vo.getCommunityId());
                communityDetail.setInterest(vo.getInterest());
                communityDetail.setLedgerCumulative(vo.getLedgerCumulative());
                communitySettleRateMap.put(vo.getCommunityId(), communityDetail);
            }
        }
        // 计算区域累计计息基数、于利息
        BigDecimal totalLedgerCumulative = BigDecimal.ZERO;
        BigDecimal totalInterest = BigDecimal.ZERO;
        for (Map.Entry<Long, GwjSettleRateVO> item : communitySettleRateMap.entrySet()) {
            totalLedgerCumulative = totalLedgerCumulative.add(item.getValue().getLedgerCumulative());
            totalInterest = totalInterest.add(item.getValue().getInterest());
        }
        // 生成计算
        String calculateFlag = generateCalculateFlag(request.getAreaId());
        // 房屋map转换为list
        List<GwjCalculateRateLog> houseLogList = houseSettleRateMap.entrySet().stream().map(item -> {
            GwjCalculateRateLog houseLog = new GwjCalculateRateLog();
            GwjSettleRateVO gwjSettleRateVO = item.getValue();
            houseLog.setDayRate(gwjSettleRateVO.getDayRate());
            houseLog.setHouseCode(item.getKey());
            houseLog.setAreaId(request.getAreaId());
            houseLog.setInterest(gwjSettleRateVO.getInterest());
            houseLog.setLedgerCumulative(gwjSettleRateVO.getLedgerCumulative());
            houseLog.setStartTime(request.getStartTime());
            houseLog.setEndTime(request.getEndTime());
            houseLog.setCommunityId(gwjSettleRateVO.getCommunityId());
            houseLog.setCalculateFlag(calculateFlag);
            houseLog.setCreateBy(SecurityUtils.getUsername());
            return houseLog;
        }).collect(Collectors.toList());
        // 新增房屋计息日志
        // 分批提交至数据库
        SqlSession houseSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GwjCalculateRateHouseMapper calculateRateHouseMapper = houseSqlSession.getMapper(GwjCalculateRateHouseMapper.class);
        // 创建房屋计息日志对象
        List<GwjCalculateRateLog> newHouseLogList = new ArrayList<GwjCalculateRateLog>();
        // 数据库插入等待时间
        Long waitTime = 5L;
        try {
            // 分批提交
            for (int i = 1; i - 1 < houseLogList.size(); i++) {
                newHouseLogList.add(houseLogList.get(i - 1));
                // 2000条房屋日志提交一次
                if (0 == i % 2000) {
                    // 批量插入房屋计息日志
                    calculateRateHouseMapper.insertBatch(newHouseLogList);
                    // 提交至数据库
                    houseSqlSession.commit();
                    // 清空对象
                    newHouseLogList.clear();
                    // 等待数据库数据插入
//                    Thread.sleep(waitTime * 1000);
                }
            }
            // 剩余数据提交
            if (ObjectUtil.isNotEmpty(newHouseLogList)) {
                // 批量插入房屋计息日志
                calculateRateHouseMapper.insertBatch(newHouseLogList);
                // 提交至数据库
                houseSqlSession.commit();
            }
        } catch (Exception e) {
            // 数据回滚
            houseSqlSession.rollback();
            throw new ServiceException(e.getMessage());
        } finally {
            // 清楚缓存
            houseSqlSession.clearCache();
            // 关闭连接
            houseSqlSession.close();
        }
        // 房屋map转换为list
        List<GwjCalculateRateLog> communityLogList = communitySettleRateMap.entrySet().stream().map(item -> {
            GwjCalculateRateLog communityLog = new GwjCalculateRateLog();
            GwjSettleRateVO gwjSettleRateVO = item.getValue();
            communityLog.setDayRate(gwjSettleRateVO.getDayRate());
            communityLog.setCommunityId(item.getKey());
            communityLog.setAreaId(request.getAreaId());
            communityLog.setLedgerCumulative(gwjSettleRateVO.getLedgerCumulative());
            communityLog.setStartTime(request.getStartTime());
            communityLog.setEndTime(request.getEndTime());
            communityLog.setCommunityId(gwjSettleRateVO.getCommunityId());
            communityLog.setCalculateFlag(calculateFlag);
            communityLog.setCreateBy(SecurityUtils.getUsername());
            return communityLog;
        }).collect(Collectors.toList());
        // 新增社区计息日志
        SqlSession communitySqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GwjCalculateRateCommunityMapper calculateRateCommunityMapper = communitySqlSession.getMapper(GwjCalculateRateCommunityMapper.class);
        // 创建社区计息日志
        List<GwjCalculateRateLog> newCommunityLogList = new ArrayList<GwjCalculateRateLog>();
        try {
            // 分批提交
            for (int i = 1; i - 1 < communityLogList.size(); i++) {
                newCommunityLogList.add(communityLogList.get(i - 1));
                // 2000条房屋日志提交一次
                if (0 == i % 2000) {
                    // 批量插入房屋计息日志
                    calculateRateCommunityMapper.insertBatch(newCommunityLogList);
                    // 提交至数据库
                    communitySqlSession.commit();
                    // 清空对象
                    newCommunityLogList.clear();
                }
            }
            // 剩余数据提交
            if (ObjectUtil.isNotEmpty(newCommunityLogList)) {
                // 批量插入房屋计息日志
                calculateRateCommunityMapper.insertBatch(newCommunityLogList);
                // 提交至数据库
                communitySqlSession.commit();
            }
        } catch (Exception e) {
            // 数据回滚
            communitySqlSession.rollback();
            throw new ServiceException(e.getMessage());
        } finally {
            // 清楚缓存
            communitySqlSession.clearCache();
            // 关闭连接
            communitySqlSession.close();
        }
        // 更新区域计息日志
        BigDecimal areaLedgerCumulative = totalLedgerCumulative;
        SqlSession baseHouseSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        GwjBaseHouseMapper baseHouseMapper = baseHouseSqlSession.getMapper(GwjBaseHouseMapper.class);
        calculateRateAreaMapper.insert(new GwjCalculateRateLog() {
            {
                setAreaId(request.getAreaId());
                setStartTime(request.getStartTime());
                setEndTime(request.getEndTime());
                setYearBenefit(request.getYearBenefit());
                setLedgerCumulative(areaLedgerCumulative);
                setDayRate(communityLogList.get(0).getDayRate());
                setCreateBy(SecurityUtils.getUsername());
            }
        });
        //更新系统计息
        gwjSysCalculateRateService.updateGwjSysCalculateRate(new GwjSysCalculateRate(){{
            setDayRate(communityLogList.get(0).getDayRate().multiply(new BigDecimal("360")));
            setId(request.getId());
        }});
        // 更新基础数据库数据
        List<String> houseCodeList = newHouseLogList.stream().map(item -> item.getHouseCode()).collect(Collectors.toList());
        List<String> editHouseCodeList = new ArrayList<>();
        try {
            // 分批查询更新基础房屋信息
            for (int i = 1; i - 1 < houseCodeList.size(); i++) {
                editHouseCodeList.add(houseCodeList.get(i - 1));
                // 分批查询插入
                if (i % 2000 == 0) {
                    // 查询基础房屋数据
                    List<GwjBaseHouse> baseHouses = houseService.selectGwjBaseListByHouseCode(editHouseCodeList.stream().toArray(String[]::new)).stream().map(item -> {
                        // 修改房屋利息
                        item.setInterestMoney(item.getInterestMoney().add(houseSettleRateMap.get(item.getHouseCode()).getInterest()));
                        item.setUpdateBy(SecurityUtils.getUsername());
                        item.setUpdateTime(new Date());
                        return item;
                    }).collect(Collectors.toList());
                    // 批量更新基础房屋数据
                    baseHouseMapper.updateBatchGwjBaseHouse(baseHouses);
                    baseHouseSqlSession.commit();
                }
            }
            // 更新剩下房屋数据
            if (ObjectUtil.isNotEmpty(editHouseCodeList)) {
                // 查询基础房屋数据
                List<GwjBaseHouse> baseHouses = houseService.selectGwjBaseListByHouseCode(editHouseCodeList.stream().toArray(String[]::new)).stream().map(item -> {
                    // 修改房屋利息
                    item.setInterestMoney(item.getInterestMoney().add(houseSettleRateMap.get(item.getHouseCode()).getInterest()));
                    item.setUpdateBy(SecurityUtils.getUsername());
                    item.setUpdateTime(new Date());
                    return item;
                }).collect(Collectors.toList());
                // 批量更新基础房屋数据
                baseHouseMapper.updateBatchGwjBaseHouse(baseHouses);
                // sql提交
                baseHouseSqlSession.commit();
            }
        } catch (Exception e) {
            // sql回滚
            baseHouseSqlSession.rollback();
            throw new ServiceException(e.getMessage());
        } finally {
            // 清除缓存
            baseHouseSqlSession.clearCache();
            // 关闭连接
            baseHouseSqlSession.close();
        }

    }

    public void interest2Money(List<GwjBaseHouse> houseList) {
        houseList.forEach(item -> item.setCurrentMoney(item.getCurrentMoney().add(item.getInterestMoney()).setScale(2, BigDecimal.ROUND_HALF_UP)));
        houseService.updateBatchGwjBaseHouse(houseList);
    }

    /**
     * 计算 房屋总账金额
     *
     * @param houses
     * @return
     */
    private BigDecimal getLedgerMoney(List<GwjBaseHouse> houses) {
        BigDecimal ledgerMoney = new BigDecimal("0.00");
        for (GwjBaseHouse house : houses) {
            ledgerMoney = ledgerMoney.add(house.getCurrentMoney()).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
        return ledgerMoney;
    }

    /**
     * 计算 日综合收益率
     *
     * @param yearBenefit          当年增值收益
     * @param yearLedgerCumulative 本年累计积数
     * @return
     */
    private BigDecimal getDayRate(BigDecimal yearBenefit, BigDecimal yearLedgerCumulative) {
        if (new BigDecimal("0.00").equals(yearLedgerCumulative)) {
            return BigDecimal.ZERO;
        }
        //231863460.61 --政府
        //231863098.47 --0.999985
        //231865381.12 --0.999995
        //231864469.46 --0.999991
        //231864240.05 --0.99999
        //231866072.52 --0.999998
        //231861932.88 --0.99998
        return yearBenefit.divide(yearLedgerCumulative, 9, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("0.99998").setScale(9, BigDecimal.ROUND_HALF_UP));
    }

    /**
     * 计算 利息金额
     *
     * @param totalLedgerCumulative
     * @param dayRate
     * @return
     */
    private BigDecimal getInterestMoney(BigDecimal totalLedgerCumulative, BigDecimal dayRate) {
        return totalLedgerCumulative.multiply(dayRate).setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 查询小区下所有房屋
     *
     * @param communityId 小区id
     * @return
     */
    private List<GwjBaseHouse> getAllHouses(Long communityId) {
        GwjBaseCommunity community = communityService.selectGwjBaseCommunityByGwjBaseCommunityId(communityId);
        if (ObjectUtil.isEmpty(community)) {
            throw new ServiceException("未找到对应的小区");
        }
        List<GwjBaseHouse> allHouses = houseService.selectGwjBaseListByBuildCodesAndAreaId(buildService.selectGwjBaseBuildListByCommunityId(communityId).stream().map(GwjBaseBuild::getBuildCode).toArray(String[]::new), community.getAreaId());
        if (CollUtil.isEmpty(allHouses)) {
            throw new ServiceException("未找到对应的房屋");
        }
        return allHouses;
    }

    /**
     * 将Date转化为localDate类型
     *
     * @param date
     * @return
     */
    private LocalDate date2LocalDate(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        return instant.atZone(zoneId).toLocalDate();
    }

    /**
     * 生成计算标识    时间戳 + 8位随机字符 + 地区id
     *
     * @param areaId 地区ID
     * @return
     */
    private String generateCalculateFlag(Long areaId) {
        String flag = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")) + RandomUtil.randomString(8);
        return StringUtils.isNotNull(areaId) ? flag + areaId : flag;
    }


    /**
     * 计算房屋利息、累计计息基数
     *
     * @param request
     * @return
     */
    private Map<String, GwjSettleRateVO> getHouseSettleRate(GwjSettleRateRequest request) {
        // 查询房屋缴存信息
        List<GwjHouseDepositVO> houseDepositList = gwjFinanceMoneyMapper.selectHousesDeposit(request);
        Map<String, List<GwjHouseDepositVO>> houseDepositMap = new HashMap<String, List<GwjHouseDepositVO>>();
        // 处理房屋缴存信息
        houseDepositList.stream().forEach(item -> {
            List<GwjHouseDepositVO> voList = houseDepositMap.get(item.getHouseCode());
            if (ObjectUtil.isEmpty(voList)) {
                houseDepositMap.put(item.getHouseCode(), ListUtil.toList(item));
            } else {
                voList.add(item);
                // 根据缴存时间排序
                voList = voList.stream().sorted(Comparator.comparing(GwjHouseDepositVO::getDealTime)).collect(Collectors.toList());
                houseDepositMap.put(item.getHouseCode(), voList);
            }
        });
        // 房屋利息、累计基数map
        Map<String, GwjSettleRateVO> houseSettleRateMap = new HashMap<>(houseDepositMap.size());
        // 计算累计计息积数
        BigDecimal totalInterestAccrual = BigDecimal.ZERO;
        // 房屋累计计息积数
        for (Map.Entry<String, List<GwjHouseDepositVO>> item : houseDepositMap.entrySet()) {
            List<GwjHouseDepositVO> voList = item.getValue();
            // 房屋累计计息积数
            BigDecimal ledgerCumulative = BigDecimal.ZERO;
            // 当只有一条缴存记录时
            if (voList.size() == 1) {
                // 结息时间扣除缴存时间的间隔天数
                long intervalDay = request.getEndTime().toEpochDay() - voList.get(0).getDealTime().toEpochDay();
                // 累加计息积数
                ledgerCumulative = voList.get(0).getDepositMoney().multiply(new BigDecimal(intervalDay));
                // 多条缴存记录时
            } else {
                int i = 0;
                if (i < voList.size() - 1) {
                    // 计算后一笔缴存记录与当前缴存记录时间间隔天数
                    long intervalDay = voList.get(i + 1).getDealTime().toEpochDay() - voList.get(i).getDealTime().toEpochDay();
                    // 累加计息积数
                    ledgerCumulative = ledgerCumulative.add(voList.get(i).getDepositMoney().multiply(new BigDecimal(intervalDay)));
                    i++;
                } else {
                    // 结息时间扣除缴存时间的间隔天数
                    long intervalDay = request.getEndTime().toEpochDay() - voList.get(0).getDealTime().toEpochDay();
                    // 累加计息积数
                    ledgerCumulative = ledgerCumulative.add(voList.get(0).getDepositMoney().multiply(new BigDecimal(intervalDay)));
                }
            }
            BigDecimal totalLedgerCumulative = ledgerCumulative;
            totalInterestAccrual = totalInterestAccrual.add(ledgerCumulative);
            // 存入房屋计息积数
            houseSettleRateMap.put(item.getKey(), new GwjSettleRateVO() {
                {
                    setLedgerCumulative(totalLedgerCumulative);
                    setBuildCode(voList.get(0).getBuildCode());
                }
            });

        }
        // 赋值房屋社区编号
        // 查询业务楼栋小区信息
        Map<String, Long> buildCommunityMap = buildService.selectGwjBaseBuildList(new GwjBaseBuild() {
            {
                // 赋值业务区域
                if (StringUtils.isNotNull(request.getAreaId())) {
                    setAreaId(request.getAreaId());
                }
            }
        }).stream().collect(Collectors.toMap(GwjBaseBuild::getBuildCode, GwjBaseBuild::getCommunityId));
        // 计算日综合收益率
        BigDecimal dayRate = getDayRate(request.getYearBenefit(), totalInterestAccrual);
        // 计算房屋利息
        for (Map.Entry<String, GwjSettleRateVO> item : houseSettleRateMap.entrySet()) {
            GwjSettleRateVO vo = item.getValue();
            vo.setInterest(getInterestMoney(vo.getLedgerCumulative(), dayRate));
            vo.setCommunityId(buildCommunityMap.get(vo.getBuildCode()));
            vo.setDayRate(dayRate);
            houseSettleRateMap.put(item.getKey(), vo);
        }
        return houseSettleRateMap;
    }

    /**
     * 获取结息开始时间
     *
     * @param areaId        地区ID
     * @param calculateTime 结算时间
     * @return 上一次结算时间
     */
    private LocalDate getStartTime(Long areaId, LocalDate calculateTime) {
        //根据条件查询上一个结算时间
        GwjSysCalculateRate lastCalculateRate = gwjSysCalculateRateService.selectLastCalculateRate(areaId, calculateTime);
        if (ObjectUtil.isNotNull(lastCalculateRate)) {
            return lastCalculateRate.getCalculateTime();
        }
        return LocalDate.of(1998, Month.OCTOBER, 1);
    }
}
